<?php

namespace common\components;

use \ZipArchive;
use Yii;
use yii\base\Component;
use yii\helpers\FileHelper;
use yii\web\UploadedFile;
use yii\base\InvalidArgumentException;

class Common extends Component{

    /**
     * 用于保存开始时间
     * @var unknown
     */
    static $tokenList = [];

    public static function genSign($secretKey, &$params = null)
    {
        if(is_null($params) || empty($params)){
            $params = ['_' => '_'];
        }
        if(!is_array($params)){
            throw new InvalidArgumentException('请求参数必须为数组');
        }

        $params['_time'] = isset($params['_time']) ? $params['_time'] : time();
        ksort($params);
        $data_str = '';
        foreach($params as $key => $value){
            if(is_null($value)){
                unset($params[$key]);
                continue;
            }
            $data_str .= strtolower($key).'='.$value;
        }

        return md5($secretKey.$data_str);
    }

    /**
     * 验证请求参数
     * @param unknown $params
     * @return boolean
     */
    public static function checkSign($params, $secretKey)
    {
        if(!isset($params['_sign']) || !isset($params['_time'])){
            return false;
        }

        if(time() - $params['_time'] > 300){  //时间限制5分钟之内
            return false;
        }
        $_sign = $params['_sign'];
        unset($params['_sign']);
        return $_sign == self::genSign($secretKey, $params);
    }

    public static function checkEmail($value){
        $pattern = '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/';
        if($value && preg_match($pattern, $value)) {
            return true;
        }
        return false;
    }

    public static function checkMenuItem($items){
        $result = [];
        if(!$items){
            return $result;
        }
        foreach ($items as $item){
            if(is_string($item)){
                $result[] = $item;
            }else{
                if(isset($item['items'])){
                    if(empty($item['items'])){
                        continue;
                    }
                    $item['items'] = self::checkMenuItem($item['items']);
                    if($item['items']){
                        $result[] = $item;
                    }
                }else if(isset($item['visible'])){
                    if($item['visible']){
                        $result[] = $item;
                    }
                }else{
                    $result[] = $item;
                }
            }
        }
        return $result;
    }

    /**
     * 全汉字
     * @param unknown $value
     * @return boolean
     */
    public static function checkChinese($value){
        if($value && preg_match("/^[\x{4e00}-\x{9fa5}]+$/u", $value)) {
            return true;
        }
        return false;
    }
    public static function checkMobile($phone){
        if($phone && preg_match('/^1\d{10}$/', $phone)){
            return true;
        }
        return false;
    }

    public static function strongPassword($password, $length = 8, $cnt = 3){
        if(strlen($password) < $length){
            return false;
        }
        $total = 0;
        $pregList = [
            '/(?=.*[a-z])/',
            '/(?=.*[A-Z])/',
            '/(?=.*\d)/',
            '/(?=.*[~!@#\$%\^&\?\\\+\.\*\(\)\{\}\[\]\|])/'
        ];
        foreach ($pregList as $preg){
            if(preg_match($preg, $password)){
                $total ++;
            }
        }
        if($total < $cnt){
            return false;
        }
        return true;
    }

    /**
     * 记录token开始时间
     * @param string $token
     */
    public static function beginTime($token = 'application'){
        self::$tokenList[$token] = microtime(true);
    }

    /**
     * 记录token结束时间
     * @param string $token
     * @package boolean $return 用于标识是否返回token消耗的时间
     */
    public static function endTime($token = 'application', $return = false){
        if(!empty(self::$tokenList[$token])){
            $startime = self::$tokenList[$token];
        }else{
            $startime = YII_BEGIN_TIME;
        }
        $speedtime = microtime(true) - $startime;
        if($return){
            return $speedtime;
        }else{
            Yii::info($token.'====>'.$speedtime.'====>'.PHP_VERSION.'====>'. (sprintf('%.3f MB', memory_get_usage() / 1048576)), 'action_time');
        }
    }
    public static function powered(){
        return '技术支持<a href="https://www.lulongkeji.com/" rel="external">路隆科技有限公司</a>';
    }

    /**
     * 生成指定长度的唯一码
     * @param $length
     * @return false|string
     */
    public static function genUniqKey($length = 20) {
        // 生成一个基于微秒的唯一ID
        $uniqueId = uniqid('', true); // 第二个参数 true 增加熵
        // 转换为十六进制并去除可能的点
        $hex = str_replace('.', '', $uniqueId);
        // 截取或填充到指定长度
        if (strlen($hex) > $length) {
            $hex = substr($hex, 0, $length);
        } else {
            $hex .= substr(md5(mt_rand()), 0, $length - strlen($hex));
        }
        return $hex;
    }
    public static function fetchRepeatMemberInArray($array) {
        // 获取去掉重复数据的数组
        $unique_arr = array_unique ( $array );
        // 获取重复数据的数组
        $repeat_arr = array_diff_assoc ( $array, $unique_arr );
        return $repeat_arr;
    }

    public static function strSplit($str, $split_length, $break = '<br />'){
        $len = mb_strlen($str, 'UTF-8');
        $count = intval(ceil($len / $split_length));
        $result = [];
        for($index = 0; $index < $count; $index ++){
            $start = $index * $split_length;
            $result[] = mb_substr($str, $start, $split_length);
        }
        return implode($break, $result);
    }

    static function checkIdCard($idCardNumber){
        $idCardNumber = strtr($idCardNumber, ['x' => 'X']);
        if (!preg_match('/^\d{18}$|^\d{17}X$/', $idCardNumber) ) {
            return false;
        }
        $idCardNumber = str_split($idCardNumber);
        $x  = array(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2);
        $y  = array(1,0,'X',9,8,7,6,5,4,3,2);
        $sum = 0;
        foreach ($x as $k=>$v) {
            $sum += $idCardNumber[$k]*$v;
        }
        return (string)$y[$sum%11]===$idCardNumber[count($idCardNumber)-1];
    }

    /**
     * @desc  im:十进制数转换成三十六机制数
     * @param (int)$num 十进制数
     * return 返回：三十六进制数
     */
    static function numToChar($num) {
        $num = intval($num);
        if ($num <= 0){
            return '';
        }
        $charArr = ['0','1','2','3','4','5','6','7','8','9','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
        $char = '';
        do {
            $key = ($num - 1) % 36;
            $char= $charArr[$key] . $char;
            $num = floor(($num - $key) / 36);
        } while ($num > 0);
        return $char;
    }

    /**
     * @desc  im:三十六进制数转换成十机制数
     * @param (string)$char 三十六进制数
     * return 返回：十进制数
     */
    static function charToNum($char){
        $charArr = ['0','1','2','3','4','5','6','7','8','9','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
        $len=strlen($char);
        for($i=0;$i<$len;$i++){
            $index = array_search($char[$i],$charArr);
            $sum += ($index+1)*pow(36,$len-$i-1);
        }
        return $sum;
    }

    static function operTerminal(){
        $user_agent = $_SERVER['HTTP_USER_AGENT'];
        $android    = (strpos($user_agent,'Android')!==false || strpos($user_agent,'Linux')!==false) ? 1 : 0;  //android终端或者uc浏览器
        $iphone     = (strpos($user_agent,'iPad')!==false || strpos($user_agent,'iPhone')!==false || strpos($user_agent,'Mac')!==false ) ? 1 : 0;     //是否为iPhone
        return ($android || $iphone) ? 'mobile' : 'pc';
    }

    /**
     * 锁住文件
     */
    static function lockFile($name, $exit = true) {
        $lockfp = fopen($name . ".lock", "w+");
        if (!$lockfp){
            echo date('Y-m-d H:i:s')."== {$name} open lockfile failed!\n";
            if($exit){
                Yii::$app->end();
            }else{
                return false;
            }
        }
        // 如果没有LOCK_NB，当前进程会一直block直到拿到这个锁
        if (!flock($lockfp, LOCK_EX | LOCK_NB)){
            echo date('Y-m-d H:i:s')."== {$name} flock failed!\n";
            if($exit){
                Yii::$app->end();
            }else{
                return false;
            }
        }
        return $lockfp;
    }

    /**
     * 生成随机数
     *
     * @param int $length
     * @return string
     */
    public static function genRand($length = 4) {
        $array = array_merge ( range ( 'a', 'z' ), range ( 'A', 'Z' ), range ( 0, 9 ) );
        shuffle ( $array );
        return implode ( '', array_slice ( $array, 0, $length ) );
    }

    public static function genRandNum($length = 4){
        $min = pow(10, $length -1) + 1;
        $max = pow(10, $length) -1;
        return mt_rand($min, $max);
    }

    static function parseZip($fileName, $destination){
        try{
            if(!file_exists($destination)){
                FileHelper::createDirectory($destination);
            }
            $zip = new ZipArchive;
            if ($zip->open($fileName) === TRUE) {
                $zip->extractTo($destination);
                $zip->close();
                return true;
            } else {
                return false;
            }
        }catch (\Exception $e){
            Yii::error([$e->getMessage(), $fileName, $destination]);
        }
    }

    static function getSuffix($file, $includeDot = true){
        $suffix = strrchr($file, '.');
        if(!$includeDot){
            $suffix = substr($suffix, 1);
        }
        return $suffix;

    }

    static function parseFile($filename){
        if(file_exists($filename)){
            $file = fopen($filename, 'r');
            while(($line = fgets($file)) !== false){
                (yield $line);
            }
        }
    }

    static function zJScandir($directory, $suffixList= [], $scanSubDir = true){

        /*
        $fileList = [];
        $Directory = new RecursiveDirectoryIterator($directory);
        $Iterator = new RecursiveIteratorIterator($Directory);
        foreach ($Iterator as $file){
            $file = $file->getPathname();
            if(in_array(self::getSuffix($file), $suffixList)){
                $fileList = $file;
            }
        }
        return $fileList;
        */

        if(!is_array($suffixList)){
            $suffixList = [$suffixList];
        }
        $directory = rtrim($directory, '/').'/';
        if (is_dir($directory)) {
            if (($handle= opendir($directory)) !== false) {
                while (false !== ($fileName = readdir($handle))) {
                    if ($fileName!= '.' && $fileName!= '..') {
                        $file = $directory.$fileName;
                        if(is_dir($file) && $scanSubDir){
                            foreach (self::zJScandir($file, $suffixList) as $file){
                                (yield $file);
                            }
                        }else{
                            if(!is_file($file)){
                                continue;
                            }
                            if($suffixList){
                                if(!in_array(self::getSuffix($file), $suffixList)){
                                    continue;
                                }
                            }
                            (yield $file);
                        }
                    }
                }
                closedir($handle);
            }
        }
    }

    static function parseXmlFileToArray($xmlFile){
        if(!file_exists($xmlFile)){
            return '';
        }
        $content = file_get_contents($xmlFile);
        if(!$content){
            return '';
        }
        return self::parseXmlToArray($content);
    }

    static function parseXmlToArray($content){
        try{
            libxml_disable_entity_loader(true);
            $values = json_decode(json_encode(simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            $values = self::convertArrayToString($values);
        }catch (\Exception $e){
            Yii::error([$content, $e->getMessage()], __METHOD__);
            $values = [];
        }
        return $values;
    }

    static function arrayToXml($arr, $root = 'xml')
    {
        $xml = "<{$root}>";
        foreach ($arr as $key => $val) {
            if (is_array($val)) {
                $xml .= "<" . $key . ">" . self::arrayToXml($val) . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</{$root}>";
        return $xml;
    }

    /**
     * xml转换数组后，字段值为空的字段被转换成了空数组，现在需要转换成''
     * @param unknown $array
     */
    static function convertArrayToString($array){
        foreach ($array as $key => $value){
            if(is_array($value)){
                if($value){
                    $value = self::convertArrayToString($value);
                }else{
                    $value = '';
                }
            }
            $array[$key] = $value;
        }
        return $array;
    }

    static function curlContent($url, $postFields = '', $headers = []) {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        //curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36');
        curl_setopt($curl, CURLOPT_TIMEOUT, 60);
        if($headers){
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        if(substr($url,0,5) == 'https'){
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        }
        if($postFields){
            /* if($file){
                $file = curl_file_create($file);
                $postFields['file'] = $file;
            } */
            // 指定post数据
            curl_setopt($curl, CURLOPT_POST, 1);
            // 添加变量
            curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
        }
        $result = curl_exec($curl);
        $responseCode = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
        $errNo = curl_errno($curl);
        if( ($errNo && $errNo != CURLE_OPERATION_TIMEDOUT) || $responseCode > 400){
            //忽略超时记录
            Yii::error([$url, 'curl_errno:'.$errNo, 'responseCode:'.$responseCode, $result], __METHOD__);
            $result = '';
        }
        curl_close($curl);
        return $result;
    }

    /**
     * 根据factor生成新的路径
     * @param string $factor 计算因子
     * @param string $level 子目录数
     * @param string $subLen 子目录字符数
     * @return string
     */
    public static function generalNewPath($factor, $level = 2, $subLen = 4){
        $result = '';
        if($factor && $level && $subLen){
            $len    = $level * $subLen;
            $subPath = str_pad($factor, $len, "0", STR_PAD_RIGHT);
            $subPath  = substr($subPath, -$len);
            for($index = 0; $index < $level; $index ++){
                $result .= substr($subPath, $index * $subLen, $subLen).'/';
            }
        }
        return $result;
    }

    /**
     * 保存文件
     * @param form表单中的名字 $name
     * @param 保存文件的名称前缀 $fileNamePrefix
     * @param 文件保存根目录 $rootPath
     * @param string $isImg
     * @param string $muitiFile
     * @return multitype:string
     */
    public static function saveFile($name, $fileNamePrefix, $rootPath, $isImg = false, $muitiFile = false, $rename = false, $level = 2, $subLen = 4){
        $rootPath = rtrim($rootPath, '/').'/';
        $subPath = self::generalNewPath($fileNamePrefix, $level, $subLen);
        $path = rtrim(str_replace('\\', '/', $rootPath.$subPath),'/').'/';
        try{
            FileHelper::createDirectory($path);
            $uploadFileList = [];
            if(!$muitiFile){
                $uploadFileList[] = UploadedFile::getInstanceByName($name);
            }else{
                $uploadFileList = UploadedFile::getInstancesByName($name);
            }

            if($uploadFileList){
                $fileNameList = [];
                foreach ($uploadFileList as $index => $uploadFile){
                    if(!$uploadFile){
                        continue;
                    }
                    if($isImg && !getimagesize($uploadFile->tempName)){
                        continue;
                    }
                    $suffix = '';
                    if($uploadFile->getExtension()){
                        $suffix = '.'.$uploadFile->getExtension();
                    }
                    if($rename){
                        $fileName = $fileNamePrefix.'_'.$index.$suffix;
                    }else{
                        $fileName = $uploadFile->getBaseName().$suffix;
                    }
                    if($uploadFile->saveAs($path.$fileName)){
                        $fileNameList[] = $subPath.$fileName;
                    }
                }
                if($fileNameList){
                    if($muitiFile){
                        return $fileNameList;
                    }else{
                        return $fileNameList[0];
                    }
                }
            }
        }catch (\Exception $e){
            Yii::error($e->getMessage());
        }
        return '';
    }

    public static function getLocalIP() {
        //$shellfp = popen("/sbin/ip addr show | awk '/inet / {print $2}' |grep -v 127.0.0.1 |cut -d'/' -f1 | head -1", 'r');
        $shellfp = popen("/sbin/ifconfig eth0|awk '/inet / {print $2}'|grep -v 127.0.0.1|cut -d':' -f2 | head -1", 'r');
        $localip = current(explode("\n", fread($shellfp, 100)));
        pclose($shellfp);
        return $localip;
        $preg = '/\A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\Z/';
        //获取操作系统为win2000/xp、win7的本机IP真实地址
        /* exec("ipconfig", $out, $stats);
        if (!empty($out)) {
            foreach ($out AS $row) {
                if (strstr($row, "IP") && strstr($row, ":") && !strstr($row, "IPv6")) {
                    $tmpIp = explode(":", $row);
                    if (preg_match($preg, trim($tmpIp[1]))) {
                        return trim($tmpIp[1]);
                    }
                }
            }
        } */
        if(function_exists('exec')){
            //获取操作系统为linux类型的本机IP真实地址
            exec("ifconfig", $out, $stats);
            if (!empty($out)) {
                if (isset($out[1]) && strstr($out[1], 'addr:')) {
                    $tmpArray = explode(":", $out[1]);
                    $tmpIp = explode(" ", $tmpArray[1]);
                    $tmpIp = trim($tmpIp[0]);
                    if (preg_match($preg, $tmpIp) && $tmpIp != '127.0.0.1') {
                        return $tmpIp;
                    }
                }
            }
        }
        return '127.0.0.1';
    }

    public static function getClientIp() {
        $ipaddress = '';
        if (!empty($_SERVER['HTTP_CLIENT_IP'])  && strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown')){
            $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
        }else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])  && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown')){
            $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }else if(!empty($_SERVER['HTTP_X_FORWARDED'])  && strcasecmp($_SERVER['HTTP_X_FORWARDED'], 'unknown')){
            $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
        }else if(!empty($_SERVER['HTTP_FORWARDED_FOR'])  && strcasecmp($_SERVER['HTTP_FORWARDED_FOR'], 'unknown')){
            $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
        }else if(!empty($_SERVER['HTTP_FORWARDED'])  && strcasecmp($_SERVER['HTTP_FORWARDED'], 'unknown')){
            $ipaddress = $_SERVER['HTTP_FORWARDED'];
        }else if(!empty($_SERVER['REMOTE_ADDR'])  && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')){
            $ipaddress = $_SERVER['REMOTE_ADDR'];
        }else{
            $ipaddress = '';
        }
        return $ipaddress;
    }

    static function maskStr($value, $len = 1, $showFront = true, $mask = '**', $encode = 'UTF-8'){
        if(!$value){
            return '';
        }
        if($showFront){
            return mb_substr($value, 0, $len, $encode).$mask;
        }else{
            return $mask.mb_substr($value, 0 - $len, null, $encode);
        }
    }

    static function maskEmail($value){
        if(strpos($value, '@') === false){
            return self::maskStr($value);
        }
        list($prefix, $suffix) = explode('@', $value);
        return self::maskStr($prefix, 3).'@'.$suffix;
    }

    static function cutStr($str, $length, $start = 0, $charset = 'UTF-8', $suffix = '...'){
        $str = trim($str);
        $len = mb_strlen($str, $charset);
        if(!$str || $len <= $length){
            return $str;
        }
        $str = mb_substr($str, $start, $length, $charset);
        return $str.$suffix;
    }

    static function maskNumber($value, $mask = '****', $encode = 'UTF-8'){
        if(!$value){
            return '';
        }
        $len = mb_strlen($value, $encode);
        if($len < 4){
            return mb_substr($value, 0, 2, $encode).$mask;
        } else if($len < 13){
            return mb_substr($value, 0, $len - 8, $encode).$mask.mb_substr($value, -4, null, $encode);
        }
        return mb_substr($value, 0, $len - 12).$mask.mb_substr($value, -4, null, $encode);
    }


    static function trimData($dataList){
        if(!is_array($dataList)){
            if(is_string($dataList)){
                $dataList = trim(strtr($dataList, ["\xc2\xa0" => '', '　' => '']));
            }
            return $dataList;
        }

        foreach ($dataList as $key => $value){
            if(is_array($value)){
                $dataList[$key] = self::trimData($value);
            }else{
                if(is_string($value)){
                    $dataList[$key] = trim(strtr($value, ["\xc2\xa0" => '', '　' => '']));
                }else{
                    $dataList[$key] = $value;
                }
            }
        }
        return $dataList;
    }

    /**
     * 邮件日志文件命名
     * @param number $minutes
     * @return string
     */
    static function emailLogFile($minutes = 0){
        $time           = date('Hi', time() - $minutes * 60);
        if(substr($time, -2) <= 30){
            $file = substr($time, 0, 2).'00.log';
        }else{
            $file = substr($time, 0, 2).'30.log';
        }
        return $file;
    }
    /**
     * 获取独立的配置文件
     * @param unknown $file_name
     * @return array|unknown
     */
    static function getOtherConfig($file_name){
        $conf = include Yii::getAlias("@common/config/other/".$file_name.".php");
        if(empty($conf)){
            return [];
        }
        return $conf;
    }
}